Facebook Certified Advertising API Developer
https://gyazo.com/234adea6cdefea15b2ac07af16c2696f
合格
試験の形式
選択試験(90分45問 700/1000で合格)
コーディング演習
制限時間がない
ドキュメントを参照してもよい。辞書も引ける。
いつでも演習ウィンドウを閉じて良い
試験内容
インフラストラクチャの設定(30%)
アセットとアクセス許可の設定に必要なコンセプトとプロセスの適用。
アプリレビュー申請の作成に必要なコンセプトとプロセスの適用。
クライアントに統合を提案するのに必要なコンセプト上およびプロセス上の決定。
オフラインイベントセットまたはカスタムオーディエンスの作成に必要なコンセプトとプロセスの適用。
コードの記述(44%)
データをFacebookで利用できるフォーマットに変換するコードを記述するのに必要なコンセプト上およびプロセス上の決定。
データを送信するコードを記述するのに必要なプロセス上の決定。
データのアップロードを認証するのに必要なコンセプト上およびプロセス上の決定。
広告のパフォーマンスデータを読み込むコードを記述するのに必要なコンセプト上およびプロセス上の決定。
トラブルシューティング(26%)
診断エラー/警告の解釈とトラブルシューティング。
コードと準備されたデータのトラブルシューティング。
試験
選択
apiとad managerの値とでずれがあるのはなぜ
apiはestamationが含まれるため
adを間違って消してしまった。2年分遡てデータが必要。apiで獲得する
archive
appの申請。snapcat
appの申請でなぜだめだったのか?どうすれば通るようになるのか
二つの別々のブランドがある。オフラインイベントセットは分けるべきか?
insight apiで目的の数字をクエリする系
insight apiでエラーが出たのでどこを修正すれば良いのか
コーディング
code:js
const axios = require('./axiosWrapper.js');
const crypto = require('crypto');
const data = require('./data.json');
const access_token = "EAAFkatNZAaukBAJZCgMn8f2mxSB9ohlGpNXZBkcoihUc6TA1rZC949sO5UfOMYmxNZBHu89nzmhfVNZA4W5ZAkiGumhiSFbPUUoqdYCDZCsMltwP01uz60zGusokwMJVZCurZAXF5ZAZCfFcgPxU2hfUUwI9r3geabqtT7BCzKvCOlPLTJVL0CwISqnx";
const offline_event_set_id = "244349397166269";
const fmc_name = "<INSERT YOUR FULL NAME HERE>";
const ad_account_id = "2860608610731120";
const upload_tag = FMC API Certification ${fmc_name} ${new Date().toLocaleString("en-US")};
//Helper function to hash data. Do not modify.
function hashData (text){
return crypto.createHash('sha256').update(text).digest('hex');
}
async function uploadOfflineConversions(data) {
try {
console.log(OC Upload: ${JSON.stringify(data)});
return await axios.post('<insert api url here>', data);
} catch (error) {
console.error(error);
}
}
async function createCustomAudience(data) {
try {
console.log(CA Upload: ${JSON.stringify(data)});
return await axios.post('<insert api url here>', data);
} catch (error) {
console.error(error);
}
}
async function uploadUsersToCustomAudience(audienceID, users) {
try {
return await axios.post('<insert api url here>', data);
} catch (error) {
console.error(error);
}
}
const normalizeData = (text, keyType) => {
//TODO: Update with normalization rules per key
return text;
}
//STEP 11 UPLOAD OFFLINE CONVERSIONS
//TODO: Sample starter code, feel free to remove
const events = data.transactions.map(transaction => {
const event = {};
return event;
});
async function mainThread() {
const oc_response = await uploadOfflineConversions(events);
// Step 12 Create a custom audience for all customers purchasers
const ca_response = await createCustomAudience(null);
// extract audience id from response
const ca_id = ca_response.data.id;
// add users to the new custom audience
const new_audience_response = await uploadUsersToCustomAudience(ca_id, null);
// Step 13 Create a custom audience based on rules from your offline event set
const ca_response2 = await createCustomAudience(null);
}
module.exports = {
'axios': axios,
'mainThread': mainThread
}
回答途中の関数
code:js
const crypto = require('crypto');
const data = require('./data.json');
function hashData (text){
return crypto.createHash('sha256').update(text).digest('hex');
}
const normalizeData = (text, keyType) => {
//TODO: Update with normalization rules per key
switch(keyType) {
case 'firstName':
text = text.trim().toLowerCase();
break;
case 'lastName':
text = text.trim().toLowerCase();
break;
case 'email':
text = text.trim().toLowerCase();
break;
default:
text = text.trim().toLowerCase();
}
return text;
}
const contentsReducer = (arry) => arry.reduce((acc, v) => {
//find alrady exists content
const tmp = acc.find(e => e.id == v.sku)
if (tmp != null) {
acc = acc.map(e2 => {
if (tmp == e2) {
e2.quantity += 1;
}
return e2;
});
} else {
acc.push({
"id": v.sku,
"quantity": 1,
"price": v.price
});
}
return acc;
}, []);
const events = data.transactions.map(transaction => {
const contents = contentsReducer(transaction.lineItems)
const event = {
"event_name": "Purchase",
"event_time": Math.round( new Date(transaction.transactionDate).getTime() / 1000 ),
"contents": contents,
"value": transaction.total,
"currency": transaction.currency,
"order_id": transaction.transactionID,
"match_keys": {
"fn": hashData(normalizeData(transaction.customer.firstName, 'firstName')),
"ln": hashData(normalizeData(transaction.customer.lastName, 'lastName'))
}
};
return event;
});
// console.log(events)
// console.log(contentsReducer(data.transactions0.lineItems)) const userList = data.transactions.map(transaction => {
return [
hashData(normalizeData(transaction.customer.firstName, 'firstName')),
hashData(normalizeData(transaction.customer.lastName, 'lastName')),
hashData(normalizeData(transaction.customer.email, 'email'))
]
})
console.log(userList)
結構カスタムオーディエンスの作成などで手間取って時間かかった